package fr.univ_paris8.iut.linc.align;



import java.util.ArrayList;
import java.util.Vector;

import net.didion.jwnl.data.IndexWord;
import net.didion.jwnl.data.POS;
import net.didion.jwnl.dictionary.Dictionary;

import org.semanticweb.owl.align.AlignmentException;
import org.semanticweb.owl.align.Cell;

import fr.inrialpes.exmo.ontosim.string.JWNLDistances;
import fr.inrialpes.exmo.ontosim.string.StringDistances;

public class Similarity {
	
	SimpleAlignment sa;	
	ComplexAlignment ca;
	StringDistances sDist;
	private static final double MAXIMUM_DISTANCE = 0.95;	
	static ArrayList <String> InutileWords = new ArrayList<String>();
	static JWNLDistances jDist = new JWNLDistances();
	
	/**
	 * Fonction de similarité qui retourne 1 si les noms des deux entités sont identiques

	 */
	public double SimEqualDistance (Entity e1, Entity e2){
				
		return (1-sDist.equalDistance(e1.getLabel().toLowerCase(), e2.getLabel().toLowerCase()));
		
	}

	/**
	 * Fonction de similarité qui prend en compte l'identité entre les sous-chaines constituant les labels des entités

	 */
	public double SimSubStringDistance (Entity e1, Entity e2){
		double Sim = 0.0;
		if (((e1.getLabel().equals("owl:Thing"))||(e1.getLabel().equals("rdfs:Literal")))
					&&((e2.getLabel().equals("owl:Thing"))||(e2.getLabel().equals("rdfs:Literal"))))
						Sim = 1;
			else if ((!(e1.getLabel().equals("owl:Thing"))&&(!e1.getLabel().equals("rdfs:Literal")))
					&&(!(e2.getLabel().equals("owl:Thing"))&&(!e2.getLabel().equals("rdfs:Literal"))))
			Sim=1-sDist.subStringDistance(e1.getLabel().toLowerCase(), e2.getLabel().toLowerCase());
			
		return Sim;
		
	}

	
	
	/**
	 * Fonction de similarité qui permet d'exploiter la ressource linguistique WordNet
	 */

	public static double simWordNet( Entity e1, Entity e2 ) {
        Dictionary dictionary = Dictionary.getInstance();
        double sim = 0.0;
        double dists1s2;
        IndexWord index = null;
        buildTable(InutileWords);
       
        if (((e1.getLabel().equals("owl:Thing"))||(e1.getLabel().equals("rdfs:Literal")))
				&&((e2.getLabel().equals("owl:Thing"))||(e2.getLabel().equals("rdfs:Literal")))){
					
        	
        	return -1;}
        
        else if ((!(e1.getLabel().equals("owl:Thing"))&&(!e1.getLabel().equals("rdfs:Literal")))
					&&(!(e2.getLabel().equals("owl:Thing"))&&(!e2.getLabel().equals("rdfs:Literal")))){
        
        
        Vector<String> t1 = StringDistances.tokenize( e1.getLabel() );
	    Vector<String> t2 = StringDistances.tokenize( e2.getLabel() );
		t1 = reduceString(t1,InutileWords);
		t2=reduceString(t2,InutileWords);
		
		String l1= ComposeString(t1);
		String l2= ComposeString(t2);
		
		dists1s2 =simWuPalmer(t1, t2);
        
        if (dists1s2 > MAXIMUM_DISTANCE) return (dists1s2);
        
        if ( l1.equals(l2) || l1.toLowerCase().equals(l2.toLowerCase())) {
            return 1;
        } else {
            if (l1.equals(l1.toUpperCase()) || l1.equals(l1.toLowerCase())) {
                try {
                    // Lookup for first string
                    index = dictionary.lookupIndexWord(POS.NOUN, l1);
                    if (index == null) {
                        index = dictionary.lookupIndexWord(POS.ADJECTIVE, l1);
                    }
                    if (index == null) {
                        index = dictionary.lookupIndexWord(POS.VERB, l1);
		    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                    System.exit(-1);
                }
                // if not found in the dictionary
                if ( index == null ) return (dists1s2);
                else sim = jDist.compareComponentNames(l1, l2);
            }
            else sim = jDist.compareComponentNames(l1, l2);
        }
        // return sim;
         return Math.max(sim, dists1s2);
    }
        else return 0;
	}
	
	

	private static double simWuPalmer( Vector<String> s1, Vector<String> s2 )  {
		double sim=0.0;
		double wup=0.0;
		
	    for (int i = 0; i<s1.size();i++)
	    	for (int j =0;j<s2.size();j++){
	    		try{
	    			wup = jDist.wuPalmerSimilarity(s1.get(i), s2.get(j));
	    		}
	    		catch (NullPointerException e){
	    			wup=0;
	    		}
	    		
	    		sim=sim+wup;
	    	}
	    
		return sim/(s1.size()*s2.size());
	
	}
	
    
    private static Vector<String>  reduceString(Vector<String> ch, ArrayList <String> InutileWords){
		Vector<String> res = new Vector<String>();
		for (int i = 0; i<ch.size();i++)
	    	if (InutileWords.contains(ch.get(i)))
	    		ch.remove(i);
		//for (int i = 0; i<ch.size();i++)
			//res=res+"_"+ch.get(i).toLowerCase();
		
		
		
		return ch;
	}
    
    private static String ComposeString(Vector<String> ch){
		String res = null;
    	for (int i = 0; i<ch.size();i++)
    		if (res==null)
    			res=ch.get(i);
    		else
    			res=res+"_"+ch.get(i).toLowerCase();
		
			
		return res;
	}
    
    /* builds the vector that contains all the information or the articles,
     * prepositions and other words to be elimintated a string or gloss
     * during the call to reduceString()
    */
    private static void buildTable(ArrayList <String> InutileWords)
    {
    	
    	InutileWords.add("a");
    	InutileWords.add("an");
    	InutileWords.add("the");
    	InutileWords.add("or");
    	InutileWords.add("no");
    	InutileWords.add("very");
    	InutileWords.add("so");
    	InutileWords.add("at");
    	InutileWords.add("who");
    	InutileWords.add("in");
    	InutileWords.add("as");
        InutileWords.add("by");
        InutileWords.add("to");
        InutileWords.add("for");
        InutileWords.add("from");
        InutileWords.add("on");
        InutileWords.add("off");
        InutileWords.add("than");
        InutileWords.add("with");
        InutileWords.add("of");
        InutileWords.add("that");
        InutileWords.add("is");
        InutileWords.add("has");
        InutileWords.add("been");
        InutileWords.add("it");
        InutileWords.add("someone");
        InutileWords.add("which");
        InutileWords.add("can");
        InutileWords.add("be");
        
      }
	
	
	/**
	 * Fonction de similarité qui exploite les mesures de similarité retournées par les aligneurs simples

	 */
	public double SimAlignment (Entity e1, Entity e2) throws AlignmentException{
		double Sim = 0.0;
		
			if ((((e1).getLabel().equals("owl:Thing"))||(e1.getLabel().equals("rdfs:Literal")))
				&&((e2.getLabel().equals("owl:Thing"))||(e2.getLabel().equals("rdfs:Literal"))))
					Sim = 1;
			else if ((!(e1.getLabel().equals("owl:Thing"))&&(!e1.getLabel().equals("rdfs:Literal")))
					&&(!(e2.getLabel().equals("owl:Thing"))&&(!e2.getLabel().equals("rdfs:Literal"))))					
			{
				java.util.Iterator<Cell> it = sa.SimpAlignment.iterator();
				boolean trouve = false;
				while ((it.hasNext())&&(!trouve)){
					int l1 = e1.getName().length();
					int l2 = e2.getName().length();
					Cell c = it.next();
								
					
					if (((c.getObject1AsURI(sa.SimpAlignment).toString().equals(e1.getName().substring(1, l1-1)))&&
					((c.getObject2AsURI(sa.SimpAlignment).toString().equals(e2.getName().substring(1, l2-1)))))
					||((c.getObject2AsURI(sa.SimpAlignment).toString().equals(e1.getName().substring(1, l1-1)))&&
					(c.getObject1AsURI(sa.SimpAlignment).toString().equals(e2.getName().substring(1, l2-1)))))
					{
						Sim=c.getStrength();
						trouve = true;
					}
					}
			}
		
			
		return Sim;
		
	}

	
	public double SimTest (Entity e1, Entity e2){
		double Sim = 0.0;
		if (((e1.getLabel().equals("owl:Thing"))||(e2.getLabel().equals("rdfs:Literal")))
					&&((e2.getLabel().equals("owl:Thing"))||(e2.getLabel().equals("rdfs:Literal"))))
						Sim = 1;
			else
			Sim=1-jDist.basicGlossOverlap(e1.getLabel().toLowerCase(), e2.getLabel().toLowerCase());
			
		return Sim;
		
	}	


}
